<template>
  <view class="page">
    <view class="scroll-container">
      <view v-if="isLoaded && itemList.length > 0" class="list-container">
        <view v-for="(col, c) in columnNum" :key="c" class="column">
          <view v-for="(item, i) in columnList[c]" :key="i" class="item-box">
            <image :src="item.url" alt="" mode="widthFix" style="width: 100%; height: auto" />
            <view class="item-info">
              <view class="info-name">
                图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片图片
              </view>
              <view class="info-other">
                <image src="@/static/images/header.png" class="info-header" />
                <text class="info-user">用户用户用户用户用户用户用户用户用户用户用户用户用户用户</text>
                <image src="@/static/images/like.png" class="info-like" />
                <text class="info-num">12</text>
              </view>
            </view>
          </view>
        </view>
      </view>
      <u-loadmore v-if="isLoadMore" status="loading" :iconSize="28" :fontSize="28" />
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      columnNum: 2,
      itemList: [],
      columnList: [],
      isLoaded: false,
      isLoadMore: true,
    };
  },
  onLoad() {
    this.generateRandomImages(true);
  },
  onPullDownRefresh() {
    this.generateRandomImages(true);
  },
  onReachBottom() {
    this.isLoadMore = true;
    this.generateRandomImages();
  },
  methods: {
    getRandomHundred() {
      const min = 175;
      const max = 250;
      const step = 25;
      const randomMultiplier = Math.floor(Math.random() * ((max - min) / step + 1));
      return min + randomMultiplier * step;
    },

    generateRandomImages(init = false) {
      if (init) {
        this.itemList = [];
        this.columnList = [];
        this.isLoaded = false;
      }
      const baseId = this.itemList.length;
      const arr = Array.from({ length: 10 }, (_, i) => {
        let height = i === 0 ? 175 : i === 1 ? 250 : this.getRandomHundred();
        return {
          id: baseId + i + 1,
          url: `https://picsum.photos/150/${height}?random=${Math.random()}`,
          title: `图片 ${baseId + i + 1}`,
        };
      });

      if (init) {
        this.itemList = arr;
        this.distributeImagesByRealHeight();
      } else {
        this.itemList = this.itemList.concat(arr);
        this.addImagesToColumns(arr);
      }
    },

    async distributeImagesByRealHeight() {
      const imageInfoList = [];

      const promises = this.itemList.map((item) => {
        return new Promise((resolve) => {
          uni.getImageInfo({
            src: item.url,
            success: (res) => {
              const width = res.width;
              const height = res.height;
              const displayWidth = 345;
              const ratio = displayWidth / width;
              const displayHeight = height * ratio;

              imageInfoList.push({ ...item, displayHeight });
              resolve();
            },
            fail: () => {
              resolve();
            },
          });
        });
      });

      await Promise.all(promises);

      const columnHeights = Array(this.columnNum).fill(0);
      const columns = Array.from({ length: this.columnNum }, () => []);

      for (const img of imageInfoList) {
        const minIndex = columnHeights.indexOf(Math.min(...columnHeights));
        columns[minIndex].push(img);
        columnHeights[minIndex] += img.displayHeight;
      }

      this.columnList = columns;
      this.isLoaded = true;
      this.isLoadMore = false;
      uni.stopPullDownRefresh();
    },

    async addImagesToColumns(newItems) {
      const imageInfoList = [];

      const promises = newItems.map((item) => {
        return new Promise((resolve) => {
          uni.getImageInfo({
            src: item.url,
            success: (res) => {
              const width = res.width;
              const height = res.height;
              const displayWidth = 345;
              const ratio = displayWidth / width;
              const displayHeight = height * ratio;

              imageInfoList.push({ ...item, displayHeight });
              resolve();
            },
            fail: () => {
              resolve();
            },
          });
        });
      });

      await Promise.all(promises);

      const columnHeights = this.columnList.map((col) =>
        col.reduce((sum, item) => sum + (item.displayHeight || 0), 0)
      );
      const columns = this.columnList.map((col) => [...col]);

      for (const img of imageInfoList) {
        const minIndex = columnHeights.indexOf(Math.min(...columnHeights));
        columns[minIndex].push(img);
        columnHeights[minIndex] += img.displayHeight;
      }

      this.columnList = columns;
      this.isLoaded = true;
      this.isLoadMore = false;
      uni.stopPullDownRefresh();
    },
  },
};
</script>

<style lang="scss" scoped>
.page {
  box-sizing: border-box;
  background-color: #e8e8e8;
  min-height: 100vh;
  padding: 20rpx 20rpx 100rpx;
  .scroll-container {
    width: 100%;
  }
}
.list-container {
  display: flex;
  justify-content: space-between;
  .column {
    flex: 1 0;
    overflow: hidden;
    & + .column {
      margin-left: 20rpx;
    }
  }
  .item-box {
    border-radius: 8rpx;
    width: 100%;
    margin-bottom: 20rpx;
    overflow: hidden;
    background-color: #ffffff;
    .item-info {
      padding: 10rpx 20rpx;
      .info-name {
        font-size: 28rpx;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        overflow: hidden;
        text-overflow: ellipsis;
      }
      .info-other {
        padding: 10rpx;
        display: flex;
        align-items: center;
        font-size: 24rpx;
        color: #666;
        .info-header {
          border-radius: 999rpx;
          width: 30rpx;
          height: 30rpx;
          margin-right: 8rpx;
          flex-shrink: 0;
        }
        .info-user {
          flex: 1 0;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          margin-right: 8rpx;
        }
        .info-like {
          width: 28rpx;
          height: 28rpx;
          margin-right: 8rpx;
          flex-shrink: 0;
        }
        .info-num {
          font-size: 24rpx;
        }
      }
    }
  }
}
</style>
